 /*******************************************************************************
  * Copyright (c) 2003, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.navigator;

 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.util.LocalSelectionTransfer;
 import org.eclipse.jface.viewers.StructuredViewer;
 import org.eclipse.swt.dnd.DND;
 import org.eclipse.swt.dnd.DropTargetEvent;
 import org.eclipse.swt.dnd.FileTransfer;
 import org.eclipse.swt.dnd.Transfer;
 import org.eclipse.swt.dnd.TransferData;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.widgets.Item;
 import org.eclipse.ui.internal.navigator.NavigatorPlugin;
 import org.eclipse.ui.internal.navigator.dnd.NavigatorDnDService;
 import org.eclipse.ui.internal.navigator.dnd.NavigatorPluginDropAction;
 import org.eclipse.ui.part.PluginDropAdapter;
 import org.eclipse.ui.part.PluginTransfer;

 /**
  * Provides an implementation of {@link PluginDropAdapter} which uses the
  * extensions provided by the associated {@link INavigatorContentService}.
  *
  * <p>
  * Clients should not need to create an instance of this class unless they are
  * creating their own custom viewer. Otherwise, {@link CommonViewer} configures
  * its drop adapter automatically.
  * </p>
  *
  *
  * @see INavigatorDnDService
  * @see CommonDragAdapter
  * @see CommonDragAdapterAssistant
  * @see CommonDropAdapterAssistant
  * @see CommonViewer
  * @since 3.2
  */
 public final class CommonDropAdapter extends PluginDropAdapter {

     private static final Transfer[] SUPPORTED_DROP_TRANSFERS = new Transfer[] {
             LocalSelectionTransfer.getTransfer(), FileTransfer.getInstance(),
             PluginTransfer.getInstance() };

     private static final boolean DEBUG = false;

     private final INavigatorContentService contentService;

     private final NavigatorDnDService dndService;

     /**
      * Create a DropAdapter that handles a drop based on the given content
      * service and selection provider.
      *
      * @param aContentService
      * The content service this Drop Adapter is associated with
      * @param aStructuredViewer
      * The viewer this DropAdapter is associated with.
      */
     public CommonDropAdapter(INavigatorContentService aContentService,
             StructuredViewer aStructuredViewer) {
         super(aStructuredViewer);
         contentService = aContentService;
         dndService = (NavigatorDnDService) contentService.getDnDService();
     }

     /**
      *
      * @return An array of Transfers allowed by the CommonDropAdapter. Includes
      * {@link LocalSelectionTransfer#getTransfer()},
      * {@link FileTransfer#getInstance()},
      * {@link PluginTransfer#getInstance()}.
      * @see LocalSelectionTransfer
      * @see FileTransfer
      * @see PluginTransfer
      */
     public Transfer[] getSupportedDropTransfers() {
         return SUPPORTED_DROP_TRANSFERS;
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.ViewerDropAdapter#dragEnter(org.eclipse.swt.dnd.DropTargetEvent)
      */
     public void dragEnter(DropTargetEvent event) {
         super.dragEnter(event);

         for (int i = 0; i < event.dataTypes.length; i++) {
             if (LocalSelectionTransfer.getTransfer().isSupportedType(
                     event.dataTypes[i])) {
                 event.currentDataType = event.dataTypes[i];
                 return;
             }
         }

         for (int i = 0; i < event.dataTypes.length; i++) {
             if (FileTransfer.getInstance().isSupportedType(event.dataTypes[i])) {
                 event.currentDataType = event.dataTypes[i];
                 event.detail = DND.DROP_COPY;
                 return;
             }
         }

         for (int i = 0; i < event.dataTypes.length; i++) {
             if (PluginTransfer.getInstance()
                     .isSupportedType(event.dataTypes[i])) {
                 event.currentDataType = event.dataTypes[i];
                 return;
             }
         }

         event.detail = DND.DROP_NONE;

     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.swt.dnd.DropTargetAdapter#dragLeave(org.eclipse.swt.dnd.DropTargetEvent)
      */
     public void dragLeave(DropTargetEvent event) {
         super.dragLeave(event);
         if (LocalSelectionTransfer.getTransfer().isSupportedType(
                 event.currentDataType)) {
             event.data = NavigatorPluginDropAction
                     .createTransferData(contentService);
         }
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.part.PluginDropAdapter#drop(org.eclipse.swt.dnd.DropTargetEvent)
      */
     public void drop(DropTargetEvent event) {
         if (PluginTransfer.getInstance().isSupportedType(event.currentDataType)) {
             super.drop(event);
         } else {

             Object target = getCurrentTarget() != null ?
                             getCurrentTarget() : getViewer().getInput();
                             
             CommonDropAdapterAssistant[] assistants = dndService
                 .findCommonDropAdapterAssistants(target, getCurrentTransfer());

             IStatus valid = null;
             for (int i = 0; i < assistants.length; i++) {
                 try {
  
                     valid = assistants[i].validateDrop(getCurrentTarget(),
                             getCurrentOperation(), getCurrentTransfer());
                     if (valid != null && valid.isOK()) {
                         assistants[i].handleDrop(this, event,
                                 getCurrentTarget());
                         return;
                     }
                 } catch (Throwable t) {
                     NavigatorPlugin.logError(0, t.getMessage(), t);
                 }
             }
         }
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.ViewerDropAdapter#validateDrop(java.lang.Object,
      * int, org.eclipse.swt.dnd.TransferData)
      */
     public boolean validateDrop(Object aDropTarget, int theDropOperation,
             TransferData theTransferData) {

         if (DEBUG) {
             System.out.println("CommonDropAdapter.validateDrop (begin)"); //$NON-NLS-1$
 }

         boolean result = false;

         IStatus valid = null;

         if (super.validateDrop(aDropTarget, theDropOperation, theTransferData)) {
             result = true;
         } else {

             Object target = aDropTarget != null ? aDropTarget : getViewer().getInput();
             CommonDropAdapterAssistant[] assistants = dndService
                     .findCommonDropAdapterAssistants(target,
                             theTransferData);
             if (DEBUG) {
                 System.out
                         .println("CommonDropAdapter.validateDrop found " + assistants.length + " drop assistants"); //$NON-NLS-1$//$NON-NLS-2$
 for(int i=0; i<assistants.length; i++)
                     System.out.println("CommonDropAdapter.validateDrop :" + assistants[i].getClass().getName()); //$NON-NLS-1$

             }
             for (int i = 0; i < assistants.length; i++) {
                 try {
                     valid = assistants[i].validateDrop(target,
                             theDropOperation, theTransferData);
                 } catch (Throwable t) {
                     NavigatorPlugin.logError(0, t.getMessage(), t);
                 }
                 if (valid != null && valid.isOK()) {
                     result = true;
                     if (DEBUG) {
                         System.out
                                 .println("CommonDropAdapter.validateDrop found \""+assistants[i].getClass().getName()+"\" would handle drop."); //$NON-NLS-1$ //$NON-NLS-2$
 }
                     break;
                 }
             }
         }

         if (DEBUG) {
             System.out
                     .println("CommonDropAdapter.validateDrop (returning " + (valid != null ? valid.getSeverity() + ": " + valid.getMessage() : "" + result) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 }


         setScrollExpandEnabled(result);
         return result;

     }

     /*
      * The visibility of the following methods is raised for downstream clients
      * (assistants).
      */

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.ViewerDropAdapter#getBounds(org.eclipse.swt.widgets.Item)
      */
     public Rectangle getBounds(Item item) {
         return super.getBounds(item);
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.ViewerDropAdapter#getCurrentLocation()
      */
     public int getCurrentLocation() {
         return super.getCurrentLocation();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.ViewerDropAdapter#getCurrentOperation()
      */
     public int getCurrentOperation() {
         return super.getCurrentOperation();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.jface.viewers.ViewerDropAdapter#getCurrentTarget()
      */
     public Object getCurrentTarget() {
         return super.getCurrentTarget();
     }

     /*
      * (non-Javadoc)
      *
      * @see org.eclipse.ui.part.PluginDropAdapter#getCurrentTransfer()
      */
     public TransferData getCurrentTransfer() {
         return super.getCurrentTransfer();
     }
     
     /**
      * Returns the position of the given event's coordinates relative to its target.
      * The position is determined to be before, after, or on the item, based on
      * some threshold value.
      *
      * @param event the event
      * @return one of the <code>LOCATION_* </code>constants defined in this class
      */
     protected int determineLocation(DropTargetEvent event) {
         if (!(event.item instanceof Item)) {
             return LOCATION_NONE;
         }
 // Item item = (Item) event.item;
 Point coordinates = new Point(event.x, event.y);
         coordinates = getViewer().getControl().toControl(coordinates);
 // if (item != null) {
 // Rectangle bounds = getBounds(item);
 // if (bounds == null) {
 // return LOCATION_NONE;
 // }
 // if ((coordinates.y - bounds.y) < 5) {
 // return LOCATION_BEFORE;
 // }
 // if ((bounds.y + bounds.height - coordinates.y) < 5) {
 // return LOCATION_AFTER;
 // }
 // }
 return LOCATION_ON;
     }

 }

